#include <unistd.h>    
#include <sys/epoll.h> 
#include <fcntl.h>     
#include <cstring>

#include "ioscheduler.h"

static bool debug = true;

namespace sylar {

// 获取当前线程的 IOManager 实例
IOManager* IOManager::GetThis() 
{
    return dynamic_cast<IOManager*>(Scheduler::GetThis());
}

// 获取指定事件的上下文
IOManager::FdContext::EventContext& IOManager::FdContext::getEventContext(Event event) 
{
    assert(event==READ || event==WRITE); // 确保事件是 READ 或 WRITE
    switch (event) 
    {
    case READ:
        return read; // 返回读事件上下文
    case WRITE:
        return write; // 返回写事件上下文
    }
    throw std::invalid_argument("Unsupported event type"); // 不支持的事件类型
}

// 重置事件上下文
void IOManager::FdContext::resetEventContext(EventContext &ctx) 
{
    ctx.scheduler = nullptr; // 清空调度器
    ctx.fiber.reset();       // 重置协程
    ctx.cb = nullptr;        // 清空回调函数
}

// 触发指定事件
void IOManager::FdContext::triggerEvent(IOManager::Event event) {
    assert(events & event); // 确保事件存在

    // 删除事件
    // 代码的意图是从 events 中移除指定的 event 标志位。
    events = (Event)(events & ~event);
    
    // 触发事件
    EventContext& ctx = getEventContext(event);
    if (ctx.cb) 
    {
        // 调用调度器的 scheduleLock 方法，调度回调函数
        ctx.scheduler->scheduleLock(&ctx.cb);
    } 
    else 
    {
        // 调用调度器的 scheduleLock 方法，调度协程
        ctx.scheduler->scheduleLock(&ctx.fiber);
    }

    // 重置事件上下文
    resetEventContext(ctx);
    return;
}

// IOManager 构造函数，初始化线程池、定时器管理器和 epoll
IOManager::IOManager(size_t threads, bool use_caller, const std::string &name): 
    Scheduler(threads, use_caller, name), TimerManager()
{
    // 创建 epoll 文件描述符
    m_epfd = epoll_create(5000);
    assert(m_epfd > 0);

    // 创建管道
    int rt = pipe(m_tickleFds);
    assert(!rt);

    // 将管道的读端添加到 epoll 中
    epoll_event event;
    event.events  = EPOLLIN | EPOLLET; // 边缘触发：事件发生时通知一次
    event.data.fd = m_tickleFds[0];

    // 设置非阻塞模式
    rt = fcntl(m_tickleFds[0], F_SETFL, O_NONBLOCK);
    assert(!rt);

    rt = epoll_ctl(m_epfd, EPOLL_CTL_ADD, m_tickleFds[0], &event);
    assert(!rt);

    // 初始化文件描述符上下文
    contextResize(32);

    // 启动调度器
    start();
}

// IOManager 析构函数，释放资源
IOManager::~IOManager() {
    stop(); // 停止调度器
    close(m_epfd); // 关闭 epoll 文件描述符
    close(m_tickleFds[0]); // 关闭管道读端
    close(m_tickleFds[1]); // 关闭管道写端

    // 删除文件描述符上下文
    for (size_t i = 0; i < m_fdContexts.size(); ++i) 
    {
        if (m_fdContexts[i]) 
        {
            delete m_fdContexts[i];
        }
    }
}

// 调整文件描述符上下文的大小
void IOManager::contextResize(size_t size) 
{
    m_fdContexts.resize(size);

    for (size_t i = 0; i < m_fdContexts.size(); ++i) 
    {
        if (m_fdContexts[i]==nullptr) 
        {
            m_fdContexts[i] = new FdContext(); // 创建新的上下文
            m_fdContexts[i]->fd = i;          // 设置文件描述符
        }
    }
}

// 添加事件到 epoll 中
int IOManager::addEvent(int fd, Event event, std::function<void()> cb) 
{
    // 尝试获取文件描述符上下文
    FdContext *fd_ctx = nullptr;
    
    std::shared_lock<std::shared_mutex> read_lock(m_mutex);
    if ((int)m_fdContexts.size() > fd) 
    {
        fd_ctx = m_fdContexts[fd];
        read_lock.unlock();
    }
    else 
    {
        read_lock.unlock();
        std::unique_lock<std::shared_mutex> write_lock(m_mutex);
        contextResize(fd * 1.5); // 扩展上下文大小
        fd_ctx = m_fdContexts[fd];
    }

    std::lock_guard<std::mutex> lock(fd_ctx->mutex);
    
    // 如果事件已存在，直接返回
    if(fd_ctx->events & event) 
    {
        return -1;
    }

    // 添加新事件到 epoll
    int op = fd_ctx->events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
    epoll_event epevent;
    epevent.events   = EPOLLET | fd_ctx->events | event;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent);
    if (rt) 
    {
        std::cerr << "addEvent::epoll_ctl failed: " << strerror(errno) << std::endl; 
        return -1;
    }

    ++m_pendingEventCount; // 增加待处理事件计数

    // 更新文件描述符上下文
    fd_ctx->events = (Event)(fd_ctx->events | event);

    // 更新事件上下文
    FdContext::EventContext& event_ctx = fd_ctx->getEventContext(event);
    assert(!event_ctx.scheduler && !event_ctx.fiber && !event_ctx.cb);
    event_ctx.scheduler = Scheduler::GetThis();
    if (cb) 
    {
        event_ctx.cb.swap(cb); // 设置回调函数
    } 
    else 
    {
        event_ctx.fiber = Fiber::GetThis(); // 设置当前协程
        assert(event_ctx.fiber->getState() == Fiber::RUNNING);
    }
    return 0;
}

// 删除指定事件
bool IOManager::delEvent(int fd, Event event) {
    // 尝试获取文件描述符上下文
    FdContext *fd_ctx = nullptr;
    
    std::shared_lock<std::shared_mutex> read_lock(m_mutex);
    if ((int)m_fdContexts.size() > fd) 
    {
        fd_ctx = m_fdContexts[fd];
        read_lock.unlock();
    }
    else 
    {
        read_lock.unlock();
        return false;
    }

    std::lock_guard<std::mutex> lock(fd_ctx->mutex);

    // 如果事件不存在，直接返回
    if (!(fd_ctx->events & event)) 
    {
        return false;
    }

    // 删除事件
    Event new_events = (Event)(fd_ctx->events & ~event);
    int op           = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
    epoll_event epevent;
    epevent.events   = EPOLLET | new_events;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent);
    if (rt) 
    {
        std::cerr << "delEvent::epoll_ctl failed: " << strerror(errno) << std::endl; 
        return -1;
    }

    --m_pendingEventCount; // 减少待处理事件计数

    // 更新文件描述符上下文
    fd_ctx->events = new_events;

    // 重置事件上下文
    FdContext::EventContext& event_ctx = fd_ctx->getEventContext(event);
    fd_ctx->resetEventContext(event_ctx);
    return true;
}

// 取消指定事件并触发回调
bool IOManager::cancelEvent(int fd, Event event) {
    // 尝试获取文件描述符上下文
    FdContext *fd_ctx = nullptr;
    
    std::shared_lock<std::shared_mutex> read_lock(m_mutex);
    if ((int)m_fdContexts.size() > fd) 
    {
        fd_ctx = m_fdContexts[fd];
        read_lock.unlock();
    }
    else 
    {
        read_lock.unlock();
        return false;
    }

    std::lock_guard<std::mutex> lock(fd_ctx->mutex);

    // 如果事件不存在，直接返回
    if (!(fd_ctx->events & event)) 
    {
        return false;
    }

    // 删除事件
    Event new_events = (Event)(fd_ctx->events & ~event);
    int op           = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
    epoll_event epevent;
    epevent.events   = EPOLLET | new_events;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent);
    if (rt) 
    {
        std::cerr << "cancelEvent::epoll_ctl failed: " << strerror(errno) << std::endl; 
        return -1;
    }

    --m_pendingEventCount; // 减少待处理事件计数

    // 触发事件
    fd_ctx->triggerEvent(event);    
    return true;
}

// 取消文件描述符上的所有事件
bool IOManager::cancelAll(int fd) {
    // 尝试获取文件描述符上下文
    FdContext *fd_ctx = nullptr;
    
    std::shared_lock<std::shared_mutex> read_lock(m_mutex);
    if ((int)m_fdContexts.size() > fd) 
    {
        fd_ctx = m_fdContexts[fd];
        read_lock.unlock();
    }
    else 
    {
        read_lock.unlock();
        return false;
    }

    std::lock_guard<std::mutex> lock(fd_ctx->mutex);
    
    // 如果没有事件，直接返回
    if (!fd_ctx->events) 
    {
        return false;
    }

    // 删除所有事件
    int op = EPOLL_CTL_DEL;
    epoll_event epevent;
    epevent.events   = 0;
    epevent.data.ptr = fd_ctx;

    int rt = epoll_ctl(m_epfd, op, fd, &epevent);
    if (rt) 
    {
        std::cerr << "IOManager::epoll_ctl failed: " << strerror(errno) << std::endl; 
        return -1;
    }

    // 触发所有事件
    if (fd_ctx->events & READ) 
    {
        fd_ctx->triggerEvent(READ);
        --m_pendingEventCount;
    }

    if (fd_ctx->events & WRITE) 
    {
        fd_ctx->triggerEvent(WRITE);
        --m_pendingEventCount;
    }

    assert(fd_ctx->events == 0); // 确保所有事件已清空
    return true;
}

// 唤醒调度器
void IOManager::tickle() 
{
    // 如果没有空闲线程，直接返回
    if(!hasIdleThreads()) 
    {
        return;
    }
    int rt = write(m_tickleFds[1], "T", 1); // 向管道写入数据，唤醒epoll_wait
    assert(rt == 1);
}

// 判断调度器是否可以停止
bool IOManager::stopping() 
{
    uint64_t timeout = getNextTimer();
    // 如果没有定时器且没有待处理事件，且调度器可以停止，则返回 true
    return timeout == ~0ull && m_pendingEventCount == 0 && Scheduler::stopping();
}

// 调度器的空闲协程
void IOManager::idle() 
{    
    static const uint64_t MAX_EVNETS = 256;
    std::unique_ptr<epoll_event[]> events(new epoll_event[MAX_EVNETS]);

    while (true) 
    {
        if(debug) std::cout << "IOManager::idle(),run in thread: " << Thread::GetThreadId() << std::endl; 

        if(stopping()) 
        {
            if(debug) std::cout << "name = " << getName() << " idle exits in thread: " << Thread::GetThreadId() << std::endl;
            break;
        }

        // 阻塞在 epoll_wait
        int rt = 0;
        while(true)
        {
            static const uint64_t MAX_TIMEOUT = 5000;
            // 获取最近的定时器超时时间作为epoll_wait的超时参数
            uint64_t next_timeout = getNextTimer();
            next_timeout = std::min(next_timeout, MAX_TIMEOUT);

            // 使用timeout进行epoll_wait
            rt = epoll_wait(m_epfd, events.get(), MAX_EVNETS, (int)next_timeout);
            // 如果被信号中断，重试
            if(rt < 0 && errno == EINTR) 
            {
                continue;
            } 
            else 
            {
                break;
            }
        };

        // 处理所有已超时的定时器回调
        std::vector<std::function<void()>> cbs;
        listExpiredCb(cbs);
        if(!cbs.empty()) 
        {
            // 调度这些超时回调
            for(const auto& cb : cbs) 
            {
                scheduleLock(cb);
            }
            cbs.clear();
        }
        
        // 处理就绪的事件
        for (int i = 0; i < rt; ++i) 
        {
            epoll_event& event = events[i];

            // 处理唤醒事件
            if (event.data.fd == m_tickleFds[0]) 
            {
                uint8_t dummy[256];
                // 边缘触发，读取所有数据
                while (read(m_tickleFds[0], dummy, sizeof(dummy)) > 0);
                continue;
            }

            // 处理其他事件
            FdContext *fd_ctx = (FdContext *)event.data.ptr;
            std::lock_guard<std::mutex> lock(fd_ctx->mutex);

            // 将 EPOLLERR 或 EPOLLHUP 转换为读或写事件
            if (event.events & (EPOLLERR | EPOLLHUP)) 
            {
                event.events |= (EPOLLIN | EPOLLOUT) & fd_ctx->events;
            }
            // 当前轮次 epoll_wait 中发生的事件
            int real_events = NONE;
            if (event.events & EPOLLIN) 
            {
                real_events |= READ;
            }
            if (event.events & EPOLLOUT) 
            {
                real_events |= WRITE;
            }

            if ((fd_ctx->events & real_events) == NONE) 
            {
                continue;
            }

            // 删除已发生的事件
            int left_events = (fd_ctx->events & ~real_events);
            int op          = left_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
            event.events    = EPOLLET | left_events;

            int rt2 = epoll_ctl(m_epfd, op, fd_ctx->fd, &event);
            if (rt2) 
            {
                std::cerr << "idle::epoll_ctl failed: " << strerror(errno) << std::endl; 
                continue;
            }

            // 调度回调并更新上下文
            if (real_events & READ) 
            {
                fd_ctx->triggerEvent(READ);
                --m_pendingEventCount;
            }
            if (real_events & WRITE) 
            {
                fd_ctx->triggerEvent(WRITE);
                --m_pendingEventCount;
            }
        } // end for

        Fiber::GetThis()->yield(); // 当前协程让出 CPU
    }
}
}